﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SocketHttpLib
{
    /// <summary>
    /// 用于映射标准流读取到gzip或deflate流的读取
    /// </summary>
    internal class PipeStream : Stream
    {
        Stream sourceStream;
        Stream bufferStream;
        int bufferWriteOffset;
        int bufferReadOffset;
        bool sourceStreamEnd;
        int chunkNum = 0;
        HttpHelper helper;
        public PipeStream(Stream sourceStream, HttpHelper helper)
        {
            this.sourceStream = sourceStream;
            this.helper = helper;
            bufferStream = new MemoryStream();
        }

        public override bool CanRead
        {
            get
            {
                return true;
            }
        }

        public override bool CanSeek
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public override bool CanWrite
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public override long Length
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public override long Position
        {
            get
            {
                throw new NotImplementedException();
            }

            set
            {
                throw new NotImplementedException();
            }
        }

        public override void Flush()
        {
            throw new NotImplementedException();
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            if (sourceStreamEnd)
                return 0;

            while (true)
            {
                var line = helper.ReadLine(sourceStream);
                var chunkHead = Encoding.ASCII.GetBytes(line + "\r\n");
                if (!line.StartsWith("\u0003") && line.Length > 0)
                {
                    //ms.Write(chunkHead, 0, chunkHead.Length);
                    var chunckSize = Convert.ToInt32(line, 16);//4090,2874
                    if (chunckSize > 0)
                    {
                        //读取一个块
                        var chunkBuffer = new byte[chunckSize];
                        using (var ms = new MemoryStream())
                        {
                            helper.StreamRead(sourceStream, ms, 0, chunckSize);
                            ms.CopyTo(bufferStream);
                        }
                        bufferStream.Write(chunkBuffer, 0, chunkBuffer.Length);
                        line = helper.ReadLine(sourceStream);
                        chunkNum++;


                        //保存本次写[缓冲流]的位置，用于读取之后还原写的位置
                        bufferWriteOffset = (int)bufferStream.Position;

                        if (count < bufferWriteOffset - bufferReadOffset)
                        {
                            //如果从上次读取[缓冲流]以来新获取的数据长度足够支付需求的长度
                            //则将其从从上次读取[缓冲流]以来的位置开始，取出需求长度的数据
                            bufferStream.Position = bufferReadOffset;
                            bufferStream.Read(buffer, offset, count);

                            //然后记录一下读取的位置方便下次从该位置开始读取
                            bufferReadOffset = (int)bufferStream.Position;

                            //接着将[缓冲流]的位置恢复到上次写的位置，为下次执行本Read函数保持流的位置
                            bufferStream.Position = bufferWriteOffset;
                            break;
                        }
                        else
                        {
                            //如果从上次读取[缓冲流]以来新获取的数据长度不足以支付需求的长度则继续从[源流]读取块到[缓冲流]
                            continue;
                        }
                    }
                    else
                    {
                        //如果[源流]已经读取完毕，就将[缓冲流]自上次读取以来剩余数据返回
                        bufferStream.Position = bufferReadOffset;
                        var bytesRead = bufferStream.Read(buffer, offset, count);
                        bufferReadOffset = (int)bufferStream.Position;
                        //标记所有块读取完毕
                        sourceStreamEnd = true;
                        return bytesRead;
                    }
                }
                else
                    break;
            }
            return count;
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new NotImplementedException();
        }

        public override void SetLength(long value)
        {
            throw new NotImplementedException();
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            throw new NotImplementedException();
        }
    }
}
